package gm.server.virtual.simulator2D;

import com.sun.scenario.scenegraph.JSGPanel;
import com.sun.scenario.scenegraph.SGGroup;
import com.sun.scenario.scenegraph.SGShape;
import com.sun.scenario.scenegraph.SGTransform;
import gm.GmLog;
import gm.editor.Dialogs;
import gm.editor.DoubleJSlider;
import gm.server.HoleTester;
import gm.server.Machine;
import gm.server.Motor;
import gm.server.MotorStepEvent;
import gm.server.Server;
import gm.server.WorkingArea;
import gm.server.WorkingAreaCornerChangeEvent;
import gm.server.WrongPositionException;
import gm.server.geom.Vector2;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.RasterFormatException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.DecimalFormat;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;

/**
 * Kanava megjelenítő alaposztálya.
 *
 * @author imruf84
 */
public class ScenePanel extends javax.swing.JPanel {

    /**
     * Kanava tárolója.
     */
    private final JSGPanel scenePanel = new JSGPanel();
    /**
     * Nagyítási faktor.
     */
    private final Point2D scale = new Point2D.Double(1, 0);
    /**
     * Eltolás mértéke.
     */
    private final Point2D translate = new Point2D.Double();
    /**
     * Kanava transzformációja.
     */
    private final SGTransform.Affine transformation = SGTransform.createAffine(null, null);
    /**
     * Nagyító csúszkája.
     */
    private DoubleJSlider zoomSlider = new DoubleJSlider(1, 30, 1, 1);
    /**
     * Jelenet tárolója.
     */
    private final SGGroup scene = new SGGroup();
    /**
     * Kanava képe.
     */
    private final KanavaImage kanavaImage = new KanavaImage();
    /**
     * Munkaterület.
     */
    private WorkingAreaComponent workingArea;
    /**
     * Végpont képének a megjelenítője.
     */
    private final ImagePane tipImagePane = new ImagePane();
    /**
     * Szerver.
     */
    private final Server server;
    /**
     * Végpont.
     */
    private TipComponent tip;

    /**
     * Konstruktor.
     *
     * @param server szerver
     */
    public ScenePanel(final Server server) {

        this.server = server;
        initComponents();

        // Görgetés sebességének a meghatározása.
        int WHEEL_SCROLL_SIZE = 10;
        this.optionsScrollPane.getHorizontalScrollBar().setUnitIncrement(WHEEL_SCROLL_SIZE);
        this.optionsScrollPane.getVerticalScrollBar().setUnitIncrement(WHEEL_SCROLL_SIZE);

        zoomSlider.addChangeListener(new javax.swing.event.ChangeListener() {
            @Override
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                scale.setLocation(zoomSlider.getDoubleValue(), 0);
                updateTransformation();
            }
        });
        zoomPanel.add(zoomSlider);

        // Rajzterület létrehozása.
        this.mainSplitPane.setLeftComponent(scenePanel);

        // Jelenet.
        this.scenePanel.setScene(this.transformation);
        this.transformation.setChild(this.scene);

        // Nagyítás beállítása.
        this.scale.setLocation(this.zoomSlider.getDoubleValue(), 0);

        // Események.
        scenePanel.addComponentListener(new java.awt.event.ComponentAdapter() {
            @Override
            public void componentResized(java.awt.event.ComponentEvent evt) {
                updateTransformation();
            }
        });

        final Point2D dragFrom = new Point2D.Double();
        scenePanel.addMouseListener(new java.awt.event.MouseAdapter() {
            @Override
            public void mousePressed(java.awt.event.MouseEvent evt) {
                if (SwingUtilities.isMiddleMouseButton(evt)) {
                    scene.globalToLocal(evt.getPoint(), dragFrom);
                }
            }
        });
        scenePanel.addMouseMotionListener(
                new java.awt.event.MouseMotionAdapter() {
            @Override
            public void mouseMoved(MouseEvent me) {
                try {
                    Point2D p = transformation.getAffine().inverseTransform(me.getPoint(), null);
                    coordsGlobalLabel.setText("[" + new DecimalFormat("#0.0").format(p.getX()) + ";" + new DecimalFormat("#0.0").format(p.getY()) + "]");
                    coordsLocalLabel.setText("[" + new DecimalFormat("#0.0").format(p.getX()) + ";" + new DecimalFormat("#0.0").format(getServer().getMachine().getThRodsLength() - p.getY()) + "]");
                } catch (NoninvertibleTransformException ex) {
                }
            }

            @Override
            public void mouseDragged(java.awt.event.MouseEvent evt) {

                // Pan.
                if (SwingUtilities.isMiddleMouseButton(evt)) {
                    Point2D dragTo = new Point2D.Double();
                    scene.globalToLocal(evt.getPoint(), dragTo);
                    Point2D dt = new Point2D.Double(dragTo.getX() - dragFrom.getX(), dragTo.getY() - dragFrom.getY());
                    translate.setLocation(translate.getX() + dt.getX(), translate.getY() + dt.getY());
                    updateTransformation();
                    scene.globalToLocal(evt.getPoint(), dragFrom);
                }
            }
        });
        scenePanel.addMouseWheelListener(
                new java.awt.event.MouseWheelListener() {
            @Override
            public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) {
                if (evt.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
                    double newScale = Math.max(zoomSlider.getDoubleMinimum(), Math.min(zoomSlider.getDoubleMaximum(), scale.getX() - (double) evt.getWheelRotation()));
                    zoomSlider.setDoubleValue(newScale);
                }
            }
        });

        // Jelenet elemeinek a létrehozása.
        createSceneComponents();

        // Végpont képének a tárolójának a létrehozása.
        tipImagePane.setMinimumSize(tipImagePanel.getMinimumSize());
        tipImagePane.setPreferredSize(tipImagePanel.getPreferredSize());
        tipImagePanel.add(tipImagePane, BorderLayout.CENTER);

    }

    /**
     * Kanava komponenseinek a létrehozása.
     */
    public final void createSceneComponents() {

        // Kanava kép.
        scene.add(kanavaImage);
        kanavaImage.setScale(0.051);
        try {
            kanavaImage.setImage(".\\kanavas\\kanava.jpg");
        } catch (IOException ex) {
            JOptionPane.showMessageDialog(this, "Hiba a kép megnyitása során: " + ex.getLocalizedMessage(), "Hiba", JOptionPane.ERROR_MESSAGE);
        }

        Machine m = getServer().getMachine();
        //m.disableMotorActions();

        // Padló.
        SGShape floor = new SGShape();
        double thRodsDistance = m.getThRodsDistance();
        floor.setShape(new Rectangle2D.Double(-20 - thRodsDistance / 2d, -7, thRodsDistance + 40, 7));
        floor.setFillPaint(Color.GRAY);
        scene.add(floor);

        // Mechanikai elemek.
        double rpm = m.getRotationsPerMinute();
        double spr = m.getStepsPerRotation();
        final MotorComponent motorLeft = new MotorComponent(Machine.LEFT_MOTOR_ID, Machine.LEFT_MOTOR_NAME, rpm, spr);
        final Motor mLeft = m.getMotor(Machine.LEFT_MOTOR_ID);
        final MotorComponent motorRight = new MotorComponent(Machine.RIGHT_MOTOR_ID, Machine.RIGHT_MOTOR_NAME, rpm, spr);
        final Motor mRight = m.getMotor(Machine.RIGHT_MOTOR_ID);

        double thRodsLength = m.getThRodsLength();
        double thRodsDiameter = m.getThRodDiameter();
        double thRodPitch = m.getThRodPitch();
        ThreadedRodComponent thRodLeft = new ThreadedRodComponent(thRodsLength, thRodsDiameter, thRodPitch, m.getThreadedRod(Machine.LEFT_MOTOR_ID).getPosition(), motorLeft);
        scene.add(thRodLeft.getComponent());
        ThreadedRodComponent thRodRigh = new ThreadedRodComponent(thRodsLength, thRodsDiameter, thRodPitch, m.getThreadedRod(Machine.RIGHT_MOTOR_ID).getPosition(), motorRight);
        scene.add(thRodRigh.getComponent());

        NutComponent nutLeft = new NutComponent(thRodLeft);
        NutComponent nutRight = new NutComponent(thRodRigh);

        double armsLength = m.getArmsLength();
        ArmComponent armLeft = new ArmComponent(armsLength, thRodsDiameter, nutLeft);
        ArmComponent armRight = new ArmComponent(armsLength, thRodsDiameter, nutRight);

        final HeadComponent head = new HeadComponent(armLeft, armRight);
        scene.add(head.getComponent());

        double nutDistance = m.getNutDistance();
        double headDistance = m.getHeadDistance();
        double needleRadius = 1;
        tip = new TipComponent(nutLeft, nutDistance, head, headDistance, needleRadius);

        final AtomicBoolean drawLock = new AtomicBoolean();

        mLeft.addOnStepEvent(new MotorStepEvent() {
            @Override
            public void onStep(Motor m) {
                synchronized (drawLock) {
                    motorLeft.setCurrentSteps(mLeft.getCurrentStepsAbsolute(), true);
                    head.updatePosition();
                    tip.updatePosition();
                    updateTipPanel();
                }
            }
        });
        mLeft.setCurrentSteps(mLeft.getCurrentStepsAbsolute(), true);
        mRight.addOnStepEvent(new MotorStepEvent() {
            @Override
            public void onStep(Motor m) {
                synchronized (drawLock) {
                    motorRight.setCurrentSteps(mRight.getCurrentStepsAbsolute(), true);
                    head.updatePosition();
                    tip.updatePosition();
                    updateTipPanel();
                }
            }
        });
        mRight.setCurrentSteps(mRight.getCurrentStepsAbsolute(), true);

        // Munkaterület.
        workingArea = new WorkingAreaComponent(tip);
        workingArea.getComponent().setVisible(workingAreaVisibleCheckBox.isSelected());
        scene.add(workingArea.getComponent());
        m.getWorkingArea().addOnCornerChangeEvent(new WorkingAreaCornerChangeEvent() {
            @Override
            public void onCornerChange(WorkingArea wa, final int cornerIndex) {
                workingArea.storeCorner1(wa.getCorner1StepsAbsolute()[0], wa.getCorner1StepsAbsolute()[1]);
                workingArea.storeCorner2(wa.getCorner2StepsAbsolute()[0], wa.getCorner2StepsAbsolute()[1]);
                workingArea.updateComponent();
            }
        });
        m.getWorkingArea().storeCorner1(m.getWorkingArea().getCorner1StepsAbsolute()[0], m.getWorkingArea().getCorner1StepsAbsolute()[1]);
        m.getWorkingArea().storeCorner2(m.getWorkingArea().getCorner2StepsAbsolute()[0], m.getWorkingArea().getCorner2StepsAbsolute()[1]);

        // Lyuk felismerő csatolása.
        m.setHoleTestMethod(new HoleTester() {
            @Override
            public boolean isHole(double stepsL, double stepsR) {
                try {
                    return imageIsHole(getTipImage());
                } catch (WrongPositionException ex) {
                    GmLog.printError(ex);
                }

                return false;
            }
        });

        // Kanavakép panel létrehozása.
        kanavaImagePanel.add(new KanavaImagePanel(kanavaImage, this), BorderLayout.CENTER);

        // Felhasználói felület létrehozása.
        createPartsPanels();

        // Végpont frissítése.
        updateTipPanel();

    }

    /**
     * Végpont lekérdezése.
     *
     * @return végpont
     */
    public TipComponent getTip() {
        return tip;
    }

    /**
     * Lyuk tesztelése.
     *
     * @param image kép
     * @return lyuk esetén igaz, egyébként hamis
     */
    public boolean imageIsHole(final BufferedImage image) {

        int r = Math.min(image.getWidth(), image.getHeight()) / 4;
        Point O = new Point(image.getWidth() / 2, image.getHeight() / 2);
        //double count = 0;
        //double black = 0;
        for (int x = 0; x < image.getWidth(); x++) {
            for (int y = 0; y < image.getHeight(); y++) {
                // Ha a pont a körön belül van, akkor feldolgozzuk.
                if ((x - O.x) * (x - O.x) + (y - O.y) * (y - O.y) <= r * r) {
                    /*count++;
                     if (image.getRGB(x, y) == Color.BLACK.getRGB()) {
                     black++;
                     }*/
                    if (image.getRGB(x, y) == Color.WHITE.getRGB()) {
                        return false;
                    }
                }
            }
        }

        return true;
        //return (black / count) > 0.8;
    }

    /**
     * Végpont adatainak a frissítése.
     */
    public void updateTipPanel() {
        try {
            // Koordináták kiírása.
            Point2D tPosG = getTipLocation();
            tipPositionGlobalLabel.setText("[" + new DecimalFormat("#0.0").format(tPosG.getX()) + " mm; " + new DecimalFormat("#0.0").format(tPosG.getY()) + " mm]");
            Vector2 tPosL = getTip().calculatePositionLocal();
            tipPositionLocalLabel.setText("[" + new DecimalFormat("#0.0").format(tPosL.x) + " mm; " + new DecimalFormat("#0.0").format(tPosL.y) + " mm]");
            // Kép megjelenítése.
            tipImagePane.setDrawImage(getTipImage(), true);
            // Lyuk esetén jelezzük.
            imageIsHoleLabel.setText(imageIsHole(getTipImage()) ? "LYUK" : "NEM LYUK");
        } catch (WrongPositionException ex) {
        }
    }

    /**
     * Végpont képének a lekérdezése.
     *
     * @return kép
     * @throws WrongPositionException kivétel
     */
    private BufferedImage getTipImage() throws WrongPositionException {
        return getImageAtPoint(getTipLocation(), getTip().getNeedleRadius());
    }

    /**
     * Pont képének a lekérdezése.
     *
     * @param point pont
     * @pont radius sugár
     * @return végpont képe
     */
    private BufferedImage getImageAtPoint(Point2D point, double radius) {
        try {
            BufferedImage img = kanavaImage.getImage();
            if (null != img) {

                Point2D r = new Point2D.Double(radius, radius);
                Point2D tr = new Point2D.Double();
                kanavaImage.getTransform().getAffine().inverseTransform(r, tr);
                Point2D p = new Point2D.Double();
                kanavaImage.getTransform().getAffine().inverseTransform(point, p);
                Point size = new Point((img.getWidth() - (int) tr.getX()), (img.getHeight() - (int) tr.getY()));
                Point position = new Point((int) p.getX() - size.y / 2, (int) p.getY() - size.y / 2);
                BufferedImage subImg = img.getSubimage(position.x, position.y, size.y, size.y);

                return subImg;
            }

        } catch (NoninvertibleTransformException | RasterFormatException ex) {
        }

        BufferedImage i = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
        i.setRGB(0, 0, Color.WHITE.getRGB());

        return i;
    }

    /**
     * Alkatrészek felhasználói felületének a frissítése.
     */
    private void createPartsPanels() {

        // Motorok.
        motorsPanel.add(new NutPanel(getServer().getMachine().getNut(Machine.LEFT_MOTOR_ID)));
        motorsPanel.add(new NutPanel(getServer().getMachine().getNut(Machine.RIGHT_MOTOR_ID)));

        updateOptionsPanelSize();
    }

    /**
     * Transzformációs mátrix frissítése.
     */
    private void updateTransformation() {
        AffineTransform at = new AffineTransform();
        at.translate(this.scenePanel.getWidth() / 2, this.scenePanel.getHeight() / 2);
        at.scale(-1, -1);
        at.scale(this.scale.getX(), this.scale.getX());
        at.translate(this.translate.getX(), this.translate.getY());
        this.transformation.setAffine(at);
    }

    /**
     * Végpont helyének lekérdezése.
     *
     * @return végpont helye
     * @throws WrongPositionException kivétel
     */
    private Point2D getTipLocation() throws WrongPositionException {
        Vector2 v = getTip().calculatePositionGlobal();
        return new Point2D.Double(v.x, v.y);
    }

    /**
     * Panel méretének frissítése a változó tartalomhoz (a görgetősávokkal van
     * gond új elemek hozzáadásakor).
     */
    private void updateOptionsPanelSize() {

        optionsPanel.doLayout();
        Component last = getLastComponent();
        optionsPanel.setPreferredSize(new Dimension(optionsPanel.getPreferredSize().width, last.getY() + last.getHeight()));
    }

    /**
     * Utolsó komponens (legalsó) lekérdezése.
     *
     * @return komponens
     */
    private Component getLastComponent() {

        Component cLast = getComponent(0);
        for (Component c : optionsPanel.getComponents()) {
            if (c.getY() > cLast.getY()) {
                cLast = c;
            }
        }

        return cLast;
    }

    /**
     * Szerver lekérdezése.
     *
     * @return szerver
     */
    public Server getServer() {
        return server;
    }

    /**
     * Jelenet lekérdezése.
     *
     * @return jelenet
     */
    public SGGroup getScene() {
        return scene;
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        mainSplitPane = new javax.swing.JSplitPane();
        optionsScrollPane = new javax.swing.JScrollPane();
        optionsPanel = new javax.swing.JPanel();
        tipPanel = new javax.swing.JPanel();
        tipPositionGlobalLabel = new javax.swing.JLabel();
        jLabel1 = new javax.swing.JLabel();
        tipImagePanel = new javax.swing.JPanel();
        imageIsHoleLabel = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();
        tipPositionLocalLabel = new javax.swing.JLabel();
        motorsPanel = new javax.swing.JPanel();
        kanavaImagePanel = new javax.swing.JPanel();
        holesPanel = new javax.swing.JPanel();
        drawHolesFoundButton = new javax.swing.JButton();
        drawHolesNotFoundButton = new javax.swing.JButton();
        drawGroupedHolesButton = new javax.swing.JButton();
        clearHoleMarksButton = new javax.swing.JButton();
        workingAreapanelPanel = new javax.swing.JPanel();
        workingAreaVisibleCheckBox = new javax.swing.JCheckBox();
        informationPanel = new javax.swing.JPanel();
        zoomPanel = new javax.swing.JPanel();
        zoomLabel = new javax.swing.JLabel();
        jLabel4 = new javax.swing.JLabel();
        coordsLocalLabel = new javax.swing.JLabel();
        jLabel3 = new javax.swing.JLabel();
        coordsGlobalLabel = new javax.swing.JLabel();

        setMinimumSize(new java.awt.Dimension(190, 120));
        setPreferredSize(new java.awt.Dimension(255, 120));
        setLayout(new java.awt.BorderLayout());

        mainSplitPane.setResizeWeight(1.0);
        mainSplitPane.setLastDividerLocation(-1);

        optionsScrollPane.setBorder(null);
        optionsScrollPane.setMinimumSize(new java.awt.Dimension(210, 400));
        optionsScrollPane.setPreferredSize(new java.awt.Dimension(210, 400));

        optionsPanel.setMinimumSize(new java.awt.Dimension(170, 400));
        optionsPanel.setPreferredSize(new java.awt.Dimension(170, 400));

        tipPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Végpont"));

        tipPositionGlobalLabel.setText("[-;-]");

        jLabel1.setText("Globális pozíció (szimulátor):");

        tipImagePanel.setMinimumSize(new java.awt.Dimension(50, 50));
        tipImagePanel.setPreferredSize(new java.awt.Dimension(50, 50));
        tipImagePanel.setLayout(new java.awt.BorderLayout());

        imageIsHoleLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        imageIsHoleLabel.setText("-");

        jLabel2.setText("Lokális pozíció (valós):");

        tipPositionLocalLabel.setText("[-;-]");

        javax.swing.GroupLayout tipPanelLayout = new javax.swing.GroupLayout(tipPanel);
        tipPanel.setLayout(tipPanelLayout);
        tipPanelLayout.setHorizontalGroup(
            tipPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(imageIsHoleLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addComponent(tipImagePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addGroup(tipPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(tipPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(tipPositionGlobalLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(tipPositionLocalLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
            .addGroup(tipPanelLayout.createSequentialGroup()
                .addGroup(tipPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel1)
                    .addComponent(jLabel2))
                .addGap(0, 25, Short.MAX_VALUE))
        );
        tipPanelLayout.setVerticalGroup(
            tipPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(tipPanelLayout.createSequentialGroup()
                .addComponent(jLabel2)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(tipPositionLocalLabel)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jLabel1)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(tipPositionGlobalLabel)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(tipImagePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(imageIsHoleLabel)
                .addContainerGap())
        );

        motorsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Motorok"));
        motorsPanel.setLayout(new javax.swing.BoxLayout(motorsPanel, javax.swing.BoxLayout.PAGE_AXIS));

        kanavaImagePanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Kanava kép"));
        kanavaImagePanel.setLayout(new java.awt.BorderLayout());

        holesPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Lyukak, jelölések"));
        holesPanel.setLayout(new java.awt.GridLayout(0, 1));

        drawHolesFoundButton.setText("Felismert lyukak kirajzolása");
        drawHolesFoundButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                drawHolesFoundButtonActionPerformed(evt);
            }
        });
        holesPanel.add(drawHolesFoundButton);

        drawHolesNotFoundButton.setText("Nem felismert lyukak kirajzolása");
        drawHolesNotFoundButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                drawHolesNotFoundButtonActionPerformed(evt);
            }
        });
        holesPanel.add(drawHolesNotFoundButton);

        drawGroupedHolesButton.setText("Pontcsoportok kirajzolása");
        drawGroupedHolesButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                drawGroupedHolesButtonActionPerformed(evt);
            }
        });
        holesPanel.add(drawGroupedHolesButton);

        clearHoleMarksButton.setText("Jelölések törlése");
        clearHoleMarksButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                clearHoleMarksButtonActionPerformed(evt);
            }
        });
        holesPanel.add(clearHoleMarksButton);

        workingAreapanelPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Munkaterület"));
        workingAreapanelPanel.setLayout(new java.awt.GridLayout(0, 1));

        workingAreaVisibleCheckBox.setSelected(true);
        workingAreaVisibleCheckBox.setText("Munkaterület");
        workingAreaVisibleCheckBox.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                workingAreaVisibleCheckBoxStateChanged(evt);
            }
        });
        workingAreapanelPanel.add(workingAreaVisibleCheckBox);

        javax.swing.GroupLayout optionsPanelLayout = new javax.swing.GroupLayout(optionsPanel);
        optionsPanel.setLayout(optionsPanelLayout);
        optionsPanelLayout.setHorizontalGroup(
            optionsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(holesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addComponent(tipPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addComponent(motorsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addComponent(kanavaImagePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addComponent(workingAreapanelPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        optionsPanelLayout.setVerticalGroup(
            optionsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(optionsPanelLayout.createSequentialGroup()
                .addComponent(tipPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(workingAreapanelPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(motorsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(kanavaImagePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(holesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        );

        optionsScrollPane.setViewportView(optionsPanel);

        mainSplitPane.setRightComponent(optionsScrollPane);

        add(mainSplitPane, java.awt.BorderLayout.CENTER);

        informationPanel.setLayout(new javax.swing.BoxLayout(informationPanel, javax.swing.BoxLayout.LINE_AXIS));

        zoomPanel.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.LOWERED));
        zoomPanel.setMaximumSize(new java.awt.Dimension(200, 24));
        zoomPanel.setLayout(new javax.swing.BoxLayout(zoomPanel, javax.swing.BoxLayout.LINE_AXIS));

        zoomLabel.setText(" Nagyítás: ");
        zoomPanel.add(zoomLabel);

        informationPanel.add(zoomPanel);

        jLabel4.setText(" Lokális:");
        informationPanel.add(jLabel4);

        coordsLocalLabel.setText("[-;-]");
        informationPanel.add(coordsLocalLabel);

        jLabel3.setText(" Globális:");
        informationPanel.add(jLabel3);

        coordsGlobalLabel.setText("[-;-]");
        informationPanel.add(coordsGlobalLabel);

        add(informationPanel, java.awt.BorderLayout.PAGE_END);
    }// </editor-fold>//GEN-END:initComponents

    private void drawHolesFoundButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawHolesFoundButtonActionPerformed

        try {

            Class.forName("org.h2.Driver");

            try (
                    Connection con = DriverManager.getConnection("jdbc:h2:./holes;trace_level_file=0;AUTO_SERVER=TRUE", "sa", "");
                    Statement stat = con.createStatement()) {

                ResultSet rs = stat.executeQuery("SELECT globX,globY FROM holes_raw WHERE isHole");
                Point2D p = new Point2D.Double();
                while (rs.next()) {
                    p.setLocation(rs.getDouble("globX"), rs.getDouble("globY"));
                    kanavaImage.markHoleFound(p, Color.GREEN, 2);
                }

            } catch (NoninvertibleTransformException ex) {
                GmLog.printError(ex);
            }

        } catch (ClassNotFoundException | SQLException ex) {
            Dialogs.showErrorMessageDialog(this, ex.getLocalizedMessage());
        }

        scenePanel.repaint();
    }//GEN-LAST:event_drawHolesFoundButtonActionPerformed

    private void clearHoleMarksButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearHoleMarksButtonActionPerformed
        kanavaImage.clearHoleMarks();
    }//GEN-LAST:event_clearHoleMarksButtonActionPerformed

    private void workingAreaVisibleCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_workingAreaVisibleCheckBoxStateChanged
        workingArea.getComponent().setVisible(workingAreaVisibleCheckBox.isSelected());
    }//GEN-LAST:event_workingAreaVisibleCheckBoxStateChanged

    private void drawGroupedHolesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawGroupedHolesButtonActionPerformed
        try {

            Class.forName("org.h2.Driver");

            try (
                    Connection con = DriverManager.getConnection("jdbc:h2:./holes;trace_level_file=0;AUTO_SERVER=TRUE", "sa", "");
                    Statement stat = con.createStatement()) {

                ResultSet rs = stat.executeQuery("SELECT globX,globY FROM holes_grouped");
                Point2D p = new Point2D.Double();
                while (rs.next()) {
                    p.setLocation(rs.getDouble("globX"), rs.getDouble("globY"));
                    kanavaImage.markHoleFound(p, Color.MAGENTA, 2);
                }

            } catch (NoninvertibleTransformException ex) {
                GmLog.printError(ex);
            }

        } catch (ClassNotFoundException | SQLException ex) {
            Dialogs.showErrorMessageDialog(this, ex.getLocalizedMessage());
        }

        scenePanel.repaint();
    }//GEN-LAST:event_drawGroupedHolesButtonActionPerformed

    private void drawHolesNotFoundButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawHolesNotFoundButtonActionPerformed
        try {

            Class.forName("org.h2.Driver");

            try (
                    Connection con = DriverManager.getConnection("jdbc:h2:./holes;trace_level_file=0;AUTO_SERVER=TRUE", "sa", "");
                    Statement stat = con.createStatement()) {

                ResultSet rs = stat.executeQuery("SELECT globX,globY FROM holes_raw WHERE NOT isHole");
                Point2D p = new Point2D.Double();
                while (rs.next()) {
                    p.setLocation(rs.getDouble("globX"), rs.getDouble("globY"));
                    kanavaImage.markHoleFound(p, Color.RED, 2);
                }

            } catch (NoninvertibleTransformException ex) {
                GmLog.printError(ex);
            }

        } catch (ClassNotFoundException | SQLException ex) {
            Dialogs.showErrorMessageDialog(this, ex.getLocalizedMessage());
        }

        scenePanel.repaint();
    }//GEN-LAST:event_drawHolesNotFoundButtonActionPerformed


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton clearHoleMarksButton;
    private javax.swing.JLabel coordsGlobalLabel;
    private javax.swing.JLabel coordsLocalLabel;
    private javax.swing.JButton drawGroupedHolesButton;
    private javax.swing.JButton drawHolesFoundButton;
    private javax.swing.JButton drawHolesNotFoundButton;
    private javax.swing.JPanel holesPanel;
    private javax.swing.JLabel imageIsHoleLabel;
    private javax.swing.JPanel informationPanel;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JPanel kanavaImagePanel;
    private javax.swing.JSplitPane mainSplitPane;
    private javax.swing.JPanel motorsPanel;
    private javax.swing.JPanel optionsPanel;
    private javax.swing.JScrollPane optionsScrollPane;
    private javax.swing.JPanel tipImagePanel;
    private javax.swing.JPanel tipPanel;
    private javax.swing.JLabel tipPositionGlobalLabel;
    private javax.swing.JLabel tipPositionLocalLabel;
    private javax.swing.JCheckBox workingAreaVisibleCheckBox;
    private javax.swing.JPanel workingAreapanelPanel;
    private javax.swing.JLabel zoomLabel;
    private javax.swing.JPanel zoomPanel;
    // End of variables declaration//GEN-END:variables
}
